﻿using DataProcess.Interface;
using System;
using System.ComponentModel.DataAnnotations;
using System.IO.Ports;
using System.Text;
using System.Threading;

namespace DataDrive.SerialPort
{
    public class DataDrive : IDataDrive
    {
        private Config Config { get; set; }

        private System.IO.Ports.SerialPort SerialPort { get; set; }

        public event StartedHandler Started;
        public event StopedHandler Stoped;
        public event DataRecivedHandler DataRecived;
        public event ErrorNoticedHandler ErrorNoticed;
        public event WarnNoticedHandler WarnNoticed;
        public event InfoNoticedHandler InfoNoticed;

        public string Name
        {
            get
            {
                return $"串口通讯{(string.IsNullOrEmpty(Config.PortName) ? "" : $"({Config.PortName})")}";
            }
        }

        public string SourceName { get; set; }

        public bool Running
        {
            get
            {
                if (SerialPort == null) return false;
                return SerialPort.IsOpen;
            }
        }

        public DataDrive(Config config)
        {
            Config = config;
            SerialPort = new System.IO.Ports.SerialPort
            {
                RtsEnable = true,
                DtrEnable = true
            };
        }

        public void Start()
        {
            if (Config == null) return;

            if (!Config.Valided())
            {
                WarnNoticed?.Invoke($"数据驱动配置不全,无法启用驱动.详情如下:{Config.Message}");
                return;
            }
            try
            {
                if (SerialPort.IsOpen) SerialPort.Close();

                SerialPort.PortName = Config.PortName;
                SerialPort.BaudRate = Config.BaudRate;
                SerialPort.Parity = Config.Parity;
                SerialPort.DataBits = Config.DataBits;
                SerialPort.StopBits = Config.StopBits;
                SerialPort.ReadBufferSize = 4096;
                SerialPort.WriteBufferSize = 4096;
                SerialPort.DataReceived -= SerialPort_DataReceived;
                SerialPort.DataReceived += SerialPort_DataReceived;
                SerialPort.Open();
                InfoNoticed?.Invoke($"串口[{Config.PortName}]已经打开，等待数据传入");
                Started?.Invoke();
            }
            catch (Exception ex)
            {
                ErrorNoticed?.Invoke(ex.Message);
            }
        }

        private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            if (Config.LazyRead != 0)
            {
                Thread.Sleep(Config.LazyRead * 1000);
            }
            byte[] result = new byte[SerialPort.BytesToRead];
            SerialPort.Read(result, 0, result.Length);
            string str = Encoding.Default.GetString(result);
            DataRecived?.Invoke(str);
        }

        public void Stop()
        {
            if (SerialPort == null) return;
            SerialPort.Close();
            Stoped?.Invoke();
        }

        public void Dispose()
        {
            if (SerialPort == null) return;
            SerialPort.Close();
            SerialPort.Dispose();
        }
    }

    public class Config : IDataDriveConfig
    {
        /// <summary>
        /// 端口号
        /// </summary>
        [Display(Name = "端口号(*)")]
        [Required(ErrorMessage = "[端口号]必须选择")]
        public string PortName { get; set; }

        /// <summary>
        /// 波特率
        /// </summary>
        [Display(Name = "波特率")]
        public int BaudRate { get; set; } = 9600;

        /// <summary>
        /// 奇偶校验位
        /// </summary>
        [Display(Name = "校验位")]
        [Required(ErrorMessage = "[校验位]必须填写")]
        public Parity Parity { get; set; } = Parity.None;

        /// <summary>
        /// 数据位
        /// </summary>
        [Display(Name = "数据位")]
        public int DataBits { get; set; } = 8;

        /// <summary>
        /// 停止位
        /// </summary>
        [Display(Name = "停止位")]
        public StopBits StopBits { get; set; } = StopBits.One;

        [Display(Name = "延迟读取数据(秒)")]
        [Range(0, 10)]
        public int LazyRead { get; set; } = 1;

        [Display(AutoGenerateField = false)]
        public string Message { get; set; }

        public bool Valided()
        {
            if (string.IsNullOrEmpty(PortName))
            {
                Message = "[端口号]不能为空";
                return false;
            }
            return true;
        }
    }
}
